/**
 * @file Fifo.cpp
 * @author lhc (liuhc_lhc@163.com)
 * @brief
 * @version 0.1
 * @date 2024-01-28
 *
 * @copyright Copyright (c) 2024
 *
 */

#include "Fifo.h"

// 初始化环形队列
int8_t
ring_buffer_init(ring_buffer_t* buffer, uint8_t* pbuffer, ring_buffer_size_t size)
{
    if (NULL == buffer || NULL == pbuffer)
        return -1;

    if ((size & (size - 1)) != 0)
        return -1;

    buffer->read_index  = 0;
    buffer->write_index = 0;
    buffer->buffer      = pbuffer;
    buffer->size        = size;
    return 0;
}

// 入队
void ring_buffer_queue_arr(ring_buffer_t* buffer, const uint8_t* data, ring_buffer_size_t size)
{
    /* Add bytes; one by one */
    ring_buffer_size_t i;

    if ((buffer->size - ring_buffer_num_items(buffer)) <= size)
        return;

    for (i = 0; i < size; i++) /* Place data in buffer */
    {
        buffer->buffer[buffer->write_index] = data[i];
        buffer->write_index                 = ((buffer->write_index + 1) & (buffer->size - 1));
    }
}
/**
 * @brief 出队 取出一个数据
 * 
 * @param buffer 队列
 * @param data 传出参数数据
 * @return uint8_t 
*/
uint8_t ring_buffer_dequeue(ring_buffer_t* buffer, uint8_t* data)
{
    if (ring_buffer_is_empty(buffer)) /* No items */
        return 0;

    *data              = buffer->buffer[buffer->read_index];
    buffer->read_index = ((buffer->read_index + 1) & (buffer->size - 1));
    return 1;
}

// 出队 取出多个数据
ring_buffer_size_t ring_buffer_dequeue_arr(ring_buffer_t* buffer, uint8_t* data, ring_buffer_size_t len)
{
    if (ring_buffer_is_empty(buffer)) /* No items */
        return 0;

    uint8_t*           data_ptr = data;
    ring_buffer_size_t cnt      = 0;
    while ((cnt < len) && ring_buffer_dequeue(buffer, data_ptr)) {
        cnt++;
        data_ptr++;
    }
    return cnt;
}

/**
 * @brief 查看指定位置的数据
 * 
 * @param buffer 
 * @param data 
 * @param index 
 * @return uint8_t 
*/
uint8_t ring_buffer_peek(ring_buffer_t* buffer, uint8_t* data, ring_buffer_size_t index)
{
    if (index >= ring_buffer_num_items(buffer)) /* No items at index */
        return 0;

    /* Add index to pointer */
    ring_buffer_size_t data_index = ((buffer->read_index + index) & (buffer->size - 1));
    *data                         = buffer->buffer[data_index];
    return 1;
}
/**
 * @brief 查看顶端数据 但是不取出
 * 
 * @param buffer 
 * @param data 
 * @return uint8_t 
*/
uint8_t ring_buffer_peek_and_dequeue(ring_buffer_t* buffer, uint8_t* data)
{
    if (ring_buffer_is_empty(buffer)) /* No items */
        return 0;

    *data = buffer->buffer[buffer->read_index];
    return 1;
}

/**
 * Returns whether a ring buffer is empty.
 * @param buffer The buffer for which it should be returned whether it is empty.
 * @return 1 if empty; 0 otherwise.
 */
inline uint8_t ring_buffer_is_empty(ring_buffer_t* buffer)
{
    return (buffer->write_index == buffer->read_index);
}

/**
 * Returns whether a ring buffer is full.
 * @param buffer The buffer for which it should be returned whether it is full.
 * @return 1 if full; 0 otherwise.
 */
inline uint8_t ring_buffer_is_full(ring_buffer_t* buffer)
{
    return ((buffer->write_index - buffer->read_index) & (buffer->size - 1)) == (buffer->size - 1);
}

/**
 * Returns the number of items in a ring buffer.
 * @param buffer The buffer for which the number of items should be returned.
 * @return The number of items in the ring buffer.
 */
inline ring_buffer_size_t ring_buffer_num_items(ring_buffer_t* buffer)
{
    return ((buffer->write_index - buffer->read_index) & (buffer->size - 1));
}